#include "my_string.h"
size_t clx::string::npos = -1;

void clx::string::my_swap(string& s)
{
  ::swap(_str, s._str);
  ::swap(_size, s._size);
  ::swap(_capacity , s._capacity);
}

clx::string::string(const char* s)
  :_str(new char[strlen(s) + 1])
  ,_size(0)
  ,_capacity(0)
{
  strcpy(_str, s);
  _size = strlen(s);
  _capacity = _size;
}

clx::string::string(const string& s)
  :_str(nullptr)
   ,_size(0)
   ,_capacity(0)
{
  string tmp(s._str);
  my_swap(tmp);
}

clx::string& clx::string::operator=(string s)
{
  my_swap(s);
 return *this;
}

clx::string::~string()
{
  delete[] _str;
  _str = nullptr;
  _size = _capacity = 0;
}

  void clx::string_test1()
  {
    string str1("hello world");
    string str2(str1);
    string str3;
    str3 = str1;
    cout << str1.c_str() << endl;
    cout << str2.c_str() << endl;
    cout << str3.c_str() << endl; 
  }

char* clx::string::c_str()
{
  return _str;
}

char* clx::string::c_str() const 
{
  return _str;
}

char& clx::string::operator[](size_t pos)
{
  return _str[pos];
}

char clx::string::operator[](size_t pos) const
{
  return _str[pos];
}

size_t clx::string::size() const 
{
  return _size;
}
size_t clx::string::size() 
{
  return _size;
}

void clx::string_test2()
{
  string str1("hello world");
  string str2("hello Linux");
  string str3("hello Centos");
  for ( size_t i = 0; i < str1.size(); i++)
  {
    cout << str1[i] << " " ;
  }
  cout << endl;
  string::iterator it = str2.begin();
  while (it != str2.end())
  {
    cout << *it << " ";
    it++;
  }
  cout << endl;
  for (auto ch : str3)
  {
    cout << ch << " ";
  }
  cout << endl;
}


size_t clx::string::reserve(size_t n)
{
  if ( n > _capacity )
  {
    char* tmp = new char[n + 1];
    strcpy(tmp, _str);
    delete[] _str;
    _str = tmp;
    _capacity = n;
    return 1;
  }
  else if(n < _capacity)
  {
    char* tmp = new char[n+1];
    strncpy(tmp, _str, n);
    delete[] _str;
    _str = tmp;
    _str[n] = '\0';
    _capacity = n;
    _size = n;
    return 1;

  }
  else if(n == _capacity)
  {
    return 1;
  }
  return 0;
  
}

size_t clx::string::resize(size_t n, char ch)
{
  if (n > _size)
  {
    if(n > _capacity)
    {
      this->reserve(n);
    }
    memset(_str + _size, ch, n - _size);
    _str[n] = '\0';
    _size = n;
    return 1;

  }
  else 
  {
    _size = n;
    _str[n] = '\0';
    return 1;
  }
  return 0;
}

void clx::string_test3()
{
  string str1("hello world");
  str1.resize(20, 'x');
  cout << str1.reserve(30) << endl; 
  cout << str1.c_str() << endl;
}

clx::string& clx::string::push_back(char ch)
{
  if (_size == _capacity)
  {
    reserve(2 * _capacity);
  }
  _str[_size] = ch;
  _size++;
  return *this;
}

clx::string& clx::string::append(const char* s)
{
  size_t len = strlen(s);
  if (_capacity < len + _size)
  {
    reserve(len + _size);
  }
  strncpy(_str+_size, s, len);
  _size += len;
  _str[_size] = '\0';
  return *this;
}

clx::string& clx::string::insert(size_t pos, char ch)
{
   if (_capacity == _size)
   {
     reserve(2 * _capacity);
   }
   char* end = _str + _size;
   while (end != (_str + pos))
   {
     *(end + 1) = *(end);
     end--;
   }
   *(_str + pos + 1) = *(_str + pos);
   *(_str + pos) = ch;
   _size++;
   return *this;
}

clx::string& clx::string::insert(size_t pos, const char* s)
{
  size_t len = strlen(s);
  if (_capacity < len + _size)
  {
    reserve(len + _size + 1);
  }
  char* end = _str + _size + 1;
  while (end != (_str + pos))
  {
    *(end - 1 + len) = *(end -1);
    end--;
  }
  strncpy(_str + pos, s, len);
  _size = len + _size;
  return *this;

}

clx::string& clx::string::operator+=(char ch)
{
  push_back(ch);
  return  *this;
}

clx::string& clx::string::operator+=(const char* s)
{
  append(s);
  return *this;
}

void clx::string_test4()
{
  string str1("hello ");
  str1.push_back('w');
  cout << str1.c_str() << endl;
  str1.append("orld");
  cout << str1.c_str() << endl;
  str1.insert(0, "clx");
  cout << str1.c_str() << endl;
  str1.insert(str1.size(), 'c');
  cout << str1.c_str() << endl;
  str1 += '4';
  cout << str1.c_str() << endl;
  str1 += "Centos";
  cout << str1.c_str() << endl;
}

clx::string& clx::string::erase(size_t pos, size_t len)
{
  if (len == npos || pos + len >= _size)
  {
    _str[pos] = '\0';
    _size = pos;
    return *this;
  }
  size_t begin = pos + len;
  while (begin <= _size)
  {
    _str[begin - len] = _str[begin];
    begin++;
  }
  _size = pos;
  return *this;
}

clx::string& clx::string::clear()
{
  erase();
  return *this;
}

void clx::string_test5()
{
  string str1("hello world");
  str1.erase(0, 2);
  cout << str1.c_str() << endl;
  str1.erase(str1.size() - 1, 3);
  cout << str1.c_str() << endl;
  str1.clear();
  cout << str1.c_str() << endl;

}

size_t clx::string::find(char ch, size_t pos) const 
{
  for (size_t i = pos; i < _size; i++)
  {
    if (ch == _str[i])
    {
      return i;
    }
  }
  return npos;
}

size_t clx::string::find(const char* s, size_t pos) const 
{
  if (strstr(_str + pos, s) == nullptr)
  {
    return npos;
  }
  else 
  {
    return strstr(_str + pos, s) - _str;
  }
}

size_t clx::string::rfind(char ch, size_t pos) const 
{
  for (size_t end = _size -1; end >= pos && end != npos; end--)
  {
    if (_str[end] == ch)
    {
      return end;
    }
  }
  return npos;
}
size_t clx::string::rfind(const char* s, size_t pos) const 
{
  size_t len = strlen(s);
  size_t end = 0;
  for (end = _size -1 - len; end >= pos && end != npos; end--)
  {
    if(_str[end] == *s)
    {
      size_t cur = 0;
      for (cur = 0; cur < len; cur++)
      {
        if (_str[end + cur] != *(s + cur))
        {
          break;
        }
      }
      if (cur == len)
      {
        return end;
      }
    }
  }
  return npos;
}
void clx::string_test6()
{
  string str1("hello world");
  cout << str1.find('o') << endl;
  cout << str1.find("llo") << endl;
  cout << str1.find('v') << endl;
  cout << str1.rfind('h') << endl;
  cout << str1.rfind("he") << endl;
}

bool clx::operator==(const string str1, const string str2)
{
  return !strcmp(str1.c_str(), str2.c_str());
}

bool clx::operator!=(const string str1, const string str2)
{
  return strcmp(str1.c_str(), str2.c_str());
}

bool clx::operator>=(const string str1, const string str2)
{
  return (str1 == str2 || str1 > str2); 
}
bool clx::operator<=(const string str1, const string str2)
{
  return (str1 == str2 || str1 < str2); 
}
bool clx::operator>(const string str1, const string str2)
{
  return strcmp(str1.c_str(), str2.c_str());
}
bool clx::operator<(const string str1, const string str2)
{
  return strcmp(str1.c_str(), str2.c_str());
}
ostream& clx::operator<<(ostream& out, const string str)
{
  for (auto ch : str)
  {
    out << ch << " ";
  }
  out << endl;
  return out;
}
istream& clx::operator>>(istream& in , string& str)
{
  str.clear();
  char ch;
  ch = in.get();
  while( ch !=' ' && ch != '\n')
  {
   str += ch; 
    ch = in.get();
  }
  return in;
}

istream& clx::getline(istream& in , string& str)
{
  str.clear();
  char ch;
  ch = in.get();
  while(ch != '\n')
  {
   str += ch; 
    ch = in.get();
  }
  return in;
}

void clx::string_test7()
{
  string str1("hello world");
  string str2("hello Linux");
  string str3 = str1;
  string str4 = "hello Centos";
  string str5;
  string str6;
  clx::getline(cin, str6);
  cin >> str5;

  cout << (str6==str1) << endl;
  cout << (str5==str1) << endl;
  cout << (str1==str3) << endl;
  cout << (str4>=str3) << endl;
  cout << (str1!=str2) << endl;
  cout << str1;
  cout << str3;
}

















